<?php
defined('IN_MAIN') or exit('Invalid Access!');

function calc_pairing_matching($in_year, $in_month, $in_day){
/*
This function calculate the pairing and matching bonus for the input in_date. This function will get all the purchases that is the first
purchase for a particular user (upgrade of member rank also considered as first sale, second and onwards purchase for a user will be calculated 
for another commission) for the input in_date and calculate the pairing in such a way that A will pair with B, then leftover from this pairing 
will pair with C, and leftover will pair with D, and so on, until all 5 legs have been processed. The maximum number of pair for a 
particular 2-leg pairing is 10 pair per day (for eg, if leg 1 pair with leg 2, max can pair 10 pairs, then leftover will pair with leg 3 also 
at maximum 10 pairs per day). Whenever a 2-leg pair reaches a max 10 pairs, then only the biggest leftover leg will be carried forward (or pair 
with next leg). After pairing, the matching will calculate right away to the downline of the commission receiver.

On successful commission calculation, it will return boolean true, else it will return the error messages
*/

	//globalize access to pairing_matching_percent, pairing_percent_per_pair, rank_index_a_bv, max_pair_per_day, matching_bonus
	
	global $vars;
	$db=$vars["db"];
	$pairing_percent_per_pair = $vars['pairing_percent_per_pair'];
	$rank_index_a_bv = $vars['rank_index_a_bv'];
	$max_pair_per_day = $vars['max_pair_per_day'];
	$matching_bonus = $vars['matching_bonus'];
	$maintenance_percent = $vars['maintenance_percent'];
	
	$start_time=mktime(0, 0, 0, $in_month, $in_day, $in_year);
	$calc_date['start']=date('Y-m-d H:i:s', mktime(0, 0, 0, $in_month, $in_day, $in_year));
	$calc_date['end']=date('Y-m-d H:i:s', mktime(23, 59, 59, $in_month, $in_day, $in_year));
	$calc_date2['start']=date('Y-m-d H:i:s', mktime(0, 0, 0, $in_month, 1, $in_year));
	$calc_date2['end']=date('Y-m-d H:i:s', mktime(23, 59, 59, $in_month+1, 0, $in_year));
	$week_date = get_week_start_end($calc_date['start'], 'Y-m-d H:i:s');
	$week = date('W', strtotime($calc_date['end']));
	$maintain_time = strtotime($week_date['end']) + (7 * 86400);
	$maintain_year = date("Y", $maintain_time);
	$maintain_month = date("n", $maintain_time);
	$maintain_week = date("W", $maintain_time);
	echo "cur: ".date('W', strtotime($week_date['end']))." (".ndate('W').") main: $maintain_week\n";
	//matching_max_level = get the maximum of matching level
	//min_maintain = get the minimum maintenance
	$matching_max_level = count($matching_bonus);
	$min_maintain = $vars['min_maintain'];
	
	//xxx members = get all the members xxx - we don't we need to filter by maintain 200 as filter is done at reporting - that have personal maintain / purchases of more than min_maintain (200)
	//xxx members = get all the members that have maintain 200BV purchases in the month
	//members = get all the members that is activated
	$t=@mysql_num_rows($r=mysql_query("select id, rank_a from $db->users where activated='y'"));
	
	//foreach members
	for($i=0;$i<$t;$i++){
		$member = mysql_fetch_assoc($r);
		//uid = this member[id]
		$uid = $member['id'];
		//if member[rank_index] > 0
		if ($member['rank_a'] > 0){
			//member_legs = get_member_matrix_leg(this member ID, calc_date[start], calc_date[end]) //get this member all legs
			$member_legs = get_member_matrix_leg($uid, $calc_date['start'], $calc_date['end']);
			/*
				member_legs will then looks like this:
				member_legs[index][id]
				member_legs[index][position]
				member_legs[index][volume] - volume should include this day volume (1st sale of a member only) plus any carry forward from previous day if applicable
				member_legs[index][left_volume] - same with volume
				member_legs[index][avolume] - avolume should include only this day volume (1st sale of a member only), without any carry forward
				
				position is the matrix position, avolume is total purchases for this day, sort by largest volume (include carry forward) leg 1st
			*/
			//pairing_amount_per_pair = rank_index_a_bv[member[rank_index]]
			//prev_position = 0
			//cur_position = 1
			//unset max_pair_reached
			//pi = 0
			$pairing_amount_per_pair = $rank_index_a_bv[$member['rank_a']];
			$max_pairing_amount = $pairing_amount_per_pair * $max_pair_per_day;
			$prev_position = 0;
			$cur_position = 1;
			unset ($max_pair_reached);
			$pi = 0;
			do{
				//continue_pair = false
				$continue_pair = false;
				//if isset member_legs[prev_position] and isset member_legs[cur_position]
				if (isset($member_legs[$prev_position]) && isset($member_legs[$cur_position])){
					//if member_legs[prev_position][left_volume] >= pairing_amount_per_pair and member_legs[cur_position][volume] >= pairing_amount_per_pair
					if ($member_legs[$prev_position]['left_volume'] > 0 && $member_legs[$cur_position]['volume'] > 0){
						//paired_amount = the least of member_legs[prev_position][left_volume] and member_legs[cur_position][volume]
						//paired_unit = floor(paired_amount / pairing_amount_per_pair)
						$paired_amount = ($a = $member_legs[$prev_position]['left_volume']) > ($b = $member_legs[$cur_position]['volume'])? $b : $a;
						//if paired_amount > max_pairing_amount
						if ($paired_amount >= $max_pairing_amount){
							$paired_amount = $max_pairing_amount;
							$max_pair_reached[$cur_position] = true;
						}
						$paired_comm[$uid][$pi]['paired_amount'] = $paired_amount;
						$paired_comm[$uid][$pi]['leg1'] = $member_legs[$prev_position]['position'];
						$paired_comm[$uid][$pi]['leg1_id'] = $member_legs[$prev_position]['id'];
						$paired_comm[$uid][$pi]['leg1_amount'] = $member_legs[$prev_position]['left_volume'];
						$paired_comm[$uid][$pi]['leg2'] = $member_legs[$cur_position]['position'];
						$paired_comm[$uid][$pi]['leg2_id'] = $member_legs[$cur_position]['id'];
						$paired_comm[$uid][$pi]['leg2_amount'] = $member_legs[$cur_position]['left_volume'];
						$pi++;
						$member_legs[$prev_position]['left_volume'] -= $paired_amount;
						$member_legs[$cur_position]['left_volume'] -= $paired_amount;
						if ($max_pair_reached[$cur_position]){
							if ($member_legs[$prev_position]['left_volume'] < $member_legs[$cur_position]['left_volume']){
								$member_legs[$prev_position]['left_volume'] = 0;//flush smaller leg
							}else{
								$member_legs[$cur_position]['left_volume'] = 0;
							}
							//we do not need check for previous leg since if max pairing haven't reach for previous leg means the units
							//have been fully paired and no left
						}
						if ($member_legs[$prev_position]['left_volume'] < $member_legs[$cur_position]['left_volume']){
							$prev_position = $cur_position;
						}
						//cur_position += 1
						$cur_position += 1;
						//continue_pair = true
						$continue_pair = true;
					}
				}
			}while ($continue_pair);
			
			//carry forward for all legs with left_volume > 0
			for($j=0,$t2=count($member_legs);$j<$t2;$j++){
				if ($member_legs[$j]['left_volume'] > 0){
					//insert into member_cf with uid = member_legs[index][id], leg = member_legs[index][position], amount = member_legs[index][left_volume], year = year, month = month, day = day
					$sql="insert into $db->member_cf (uid, leg, amount, cdate) values ('{$member_legs[$j]['id']}', '{$member_legs[$j]['position']}', '{$member_legs[$j]['left_volume']}', '".date('Y-m-d', $start_time)."')";
					$insert_comm_detail="UID: $uid Carryforward Amount: {$member_legs[$j]['left_volume']} Leg: {$member_legs[$j]['position']} (DID: {$member_legs[$j]['id']})<br />\n";
					//if insert fail
						//record error in the variable insert_cf_error
					if(!mysql_query($sql)){
						$insert_cf_error.=$insert_comm_detail."SQL: $sql<br />\n";
					}
				}
			}
			
			//matching
			//if count(paired_comm[uid])
			if (count($paired_comm[$uid])){
				//downline_id = uid
				$downline_id = $uid;
				$level = 1;
				do{
					if (!isset($member_info[$downline_id])){
						$member_info[$downline_id] = get_user_short_detail_by_id($downline_id);
					}
					$upline_id = $member_info[$downline_id]['ref'];
					if ($upline_id){
						$sponsor_tree[$uid][$level] = $upline_id;
						$downline_id = $upline_id;
					}else{
						unset ($downline_id);
					}
					$level += 1;
				}while ($downline_id && $level <= $matching_max_level);
				
				//foreach paired_comm as uid => position_pair
				for($j=0,$t2=count($paired_comm[$uid]);$j<$t2;$j++){
					//unset pairing_id
					//pairing_comm_amount = paired_comm[uid][index][paired_unit] * pairing_bonus_per_pair
					unset ($pairing_id);
					$pairing_comm_amount = round($paired_comm[$uid][$j]['paired_amount'] * $pairing_percent_per_pair / 100, 2);
					//insert the commission into the member_comm table with type = pairing, uid = uid, volume_type = pairing_amount_per_pair, amount = pairing_comm_amount, leg1 = paired_comm[uid][index][leg1], leg1_id = paired_comm[uid][index][leg1_id], leg1_amount = paired_comm[uid][index][leg1_amount], leg2 = paired_comm[uid][index][leg2], leg2_id = paired_comm[uid][index][leg2_id], leg2_amount = paired_comm[uid][index][leg2_amount], paired_unit = paired_unit, year, month, datetime
					$sql="insert into $db->member_comm (uid, type, volume_type, amount, leg1, leg1_id, leg1_amount, leg2, leg2_id, leg2_amount, year, month, week, day, status, cdate) values ('$uid', 'p', '$pairing_amount_per_pair', '$pairing_comm_amount', '{$paired_comm[$uid][$j]['leg1']}', '{$paired_comm[$uid][$j]['leg1_id']}', '{$paired_comm[$uid][$j]['leg1_amount']}', '{$paired_comm[$uid][$j]['leg2']}', '{$paired_comm[$uid][$j]['leg2_id']}', '{$paired_comm[$uid][$j]['leg2_amount']}', '$in_year', '$in_month', '$week', '$in_day', 'confirmed', '".ndate('Y-m-d H:i:s')."')";
					//if insert fail
						//record the error in the variable insert_pair_error
					$insert_comm_detail="UID: $uid Volume Type: $pairing_amount_per_pair Amount: $pairing_comm_amount Leg 1: {$paired_comm[$uid][$j]['leg1_id']}, Leg 2: {$paired_comm[$uid][$j]['leg2_id']} No. of Pair: $paired_unit<br />\n";
					if(!mysql_query($sql)){
						$insert_pair_error.=$insert_comm_detail."SQL: $sql<br />\n";
					}else{
						$insert_pair_success.=$insert_comm_detail;
						//pairing_id = last insert id
						$pairing_id = mysql_insert_id();
					}
					$member_comm[$uid] += $pairing_comm_amount;
					
					//if isset sponsor_tree[uid]
					if (isset($sponsor_tree[$uid])){
						//foreach sponsor_tree[uid] as level => upline_id
						foreach ($sponsor_tree[$uid] as $level => $upline_id){
							//if not isset upline_info[upline_id]
							if (!isset($upline_info[$upline_id])){
								//upline_info[upline_id][sponsor] = get total downline sponsored by this upline_id before the end of month of input in_date
								//upline_info[upline_id][activated] = whether this upline_id is activated
								$upline_info[$upline_id]['sponsor'] = @mysql_result(mysql_query("select count(*) from $db->users where ref='$upline_id' and cdate<='$calc_date[end]'"), 0) or 0;
								$upline_info[$upline_id]['activated'] = $member_info[$upline_id]['activated'];
							}
							//upline_detail = upline_info[upline_id]
							$upline_detail = $upline_info[$upline_id];
							//if upline_detail[volume] >= min_maintain and upline_detail[sponsor] >= matching_bonus[level][sponsor] and upline_detail[activated]
							if ($upline_detail['sponsor'] >= $matching_bonus[$level]['sponsor'] && $upline_detail['activated'] == 'y'){
								//matching_comm_amount = round(pairing_comm_amount * matching_bonus[level][percent] / 100, 2)
								$matching_comm_percent = $matching_bonus[$level]['percent'];
								$matching_comm_amount = round($pairing_comm_amount * $matching_comm_percent / 100, 2);
								//if pairing_id
								if ($pairing_id){
									//insert the commission into the member_comm table with type = matching, pid = pairing_id, uid = upline_id, from_uid = uid, amount = matching_comm_amount, level = level, percent = matching_bonus[level], year, month, datetime
									$sql="insert into $db->member_comm (uid, from_uid, type, pid, amount, level, percent, year, month, week, day, status, cdate) values ('$upline_id', '$uid', 'm', '$pairing_id', '$matching_comm_amount', '$level', '$matching_comm_percent', '$in_year', '$in_month', '$week', '$in_day', 'confirmed', '".ndate('Y-m-d H:i:s')."')";
									//if insert fail
										//record the error in the variable insert_matching_error
									$insert_comm_detail="UID: $upline_id Pairing ID: $pairing_id Amount: $matching_comm_amount Level: $level Percent: $matching_comm_percent%<br />\n";
									if(!mysql_query($sql)){
										$insert_matching_error.=$insert_comm_detail."SQL: $sql<br />\n";
									}else{
										$insert_matching_success.=$insert_comm_detail;
									}
									$matching_comm[$upline_id] += $matching_comm_amount;
								}else{
									//record the error in the variable insert_matching_error - pairing not properly inserted
									$insert_matching_error.="UID: $uid Pairing ID: Error! Amount: $matching_comm_amount Level: $level Percent: $matching_comm_percent%<br />\n";
								}
							}
						}
					}
				}
			}
		}
	}
	
	if ($member_comm){
		foreach ($member_comm as $uid => $amount){			
			$maintain_amount = round($amount * $maintenance_percent / 100, 2);
			//insert into member_maintain with uid = uid, type = plana, comm_type = sponsor bonus, percent = maintain[plana], amount = maintain_plana, pv = maintain_value_to_pv, date
			$sql = "insert into $db->member_maintain (uid, comm_type, percent, amount, year, month, week, cdate)
			values ('$uid', 'p', '$maintenance_percent', '$maintain_amount', '$maintain_year', '$maintain_month', '$maintain_week', '".ndate()."')";
			if(!mysql_query($sql)){
				$insert_main_err.="UID: $uid, comm code: p, percent: $maintenance_percent%, amount: $maintain_amount, year: $maintain_year, month: $maintain_month, week: $maintain_week\n";
			}
			
			$actual_amount = $amount - $maintain_amount;
			if(!mysql_query($sql="update $db->users set ewallet=ewallet+$actual_amount where id='$uid' limit 1")){
				$update_ew_err.="UID: $uid, amount: $actual_amount\n";
			}elseif(!mysql_query($sql="insert into $db->member_ewallet_record (uid, type, amount, descr, cdate) values ('$uid', 'credit', '$amount', '".addslashes("Credited $vars[currency]".number_format($amount, 2)." from bulk pairing commission received.")."', '".ndate()."')")){
				$insert_ewrec_err.=$sql."\n";
			}
			
			//insert ewallet record for maintenance
			if(!mysql_query($sql="insert into $db->member_ewallet_record (uid, type, amount, descr, cdate) values ('$uid', 'debit', '$maintain_amount', '".addslashes("Debited $vars[currency]".number_format($maintain_amount, 2)." for maintenance from bulk pairing commission received.")."', '".ndate()."')")){
				$insert_ewrec_err.=$sql."\n";
			}
			
			//update member swallet = swallet + maintain_amount
			if(!mysql_query($sql="update $db->users set swallet=swallet+$maintain_amount where id='$uid' limit 1")){
				$update_sw_err.="UID: $uid, amount: $maintain_amount\n";
			}elseif(!mysql_query($sql="insert into $db->member_swallet_record (uid, type, amount, descr, cdate) values ('$uid', 'credit', '$maintain_amount', '".addslashes("Credited $vars[currency]".number_format($maintain_amount, 2)." for maintenance from bulk pairing commission received.")."', '".ndate()."')")){
				$insert_swrec_err.=$sql."\n";
			}
		}
	}
	
	if ($matching_comm){
		foreach ($matching_comm as $uid => $amount){			
			$maintain_amount = round($amount * $maintenance_percent / 100, 2);
			//insert into member_maintain with uid = uid, type = plana, comm_type = sponsor bonus, percent = maintain[plana], amount = maintain_plana, pv = maintain_value_to_pv, date
			$sql = "insert into $db->member_maintain (uid, comm_type, percent, amount, year, month, week, cdate)
			values ('$uid', 'm', '$maintenance_percent', '$maintain_amount', '$maintain_year', '$maintain_month', '$maintain_week', '".ndate()."')";
			if(!mysql_query($sql)){
				$insert_main_err.="UID: $uid, comm code: m, percent: $maintenance_percent%, amount: $maintain_amount, year: $maintain_year, month: $maintain_month, week: $maintain_week\n";
			}
			
			$actual_amount = $amount - $maintain_amount;
			if(!mysql_query($sql="update $db->users set ewallet=ewallet+$actual_amount where id='$uid' limit 1")){
				$update_ew_err.="UID: $uid, amount: $actual_amount\n";
			}elseif(!mysql_query($sql="insert into $db->member_ewallet_record (uid, type, amount, descr, cdate) values ('$uid', 'credit', '$amount', '".addslashes("Credited $vars[currency]".number_format($amount, 2)." from bulk matching commission received.")."', '".ndate()."')")){
				$insert_ewrec_err.=$sql."\n";
			}
			
			//insert ewallet record for maintenance
			if(!mysql_query($sql="insert into $db->member_ewallet_record (uid, type, amount, descr, cdate) values ('$uid', 'debit', '$maintain_amount', '".addslashes("Debited $vars[currency]".number_format($maintain_amount, 2)." for maintenance from bulk matching commission received.")."', '".ndate()."')")){
				$insert_ewrec_err.=$sql."\n";
			}
			
			//update member swallet = swallet + maintain_amount
			if(!mysql_query($sql="update $db->users set swallet=swallet+$maintain_amount where id='$uid' limit 1")){
				$update_sw_err.="UID: $uid, amount: $maintain_amount\n";
			}elseif(!mysql_query($sql="insert into $db->member_swallet_record (uid, type, amount, descr, cdate) values ('$uid', 'credit', '$maintain_amount', '".addslashes("Credited $vars[currency]".number_format($maintain_amount, 2)." for maintenance from bulk matching commission received.")."', '".ndate()."')")){
				$insert_swrec_err.=$sql."\n";
			}
		}
	}
	
	if($insert_cf_error || $insert_pair_error || $insert_matching_error || $insert_main_err){
		$status = false;
	}else{
		$status = true;
	}
	
	$errmsg = ($insert_cf_error? "\nFailed Recording Carry Forward:\n\n$insert_cf_error" : "").
	($insert_pair_error? "Failed Pairing Commission Calculation:<br />\n<br />\n$insert_pair_error" : "").
	($insert_matching_error? "Failed Matching Commission Calculation:<br />\n<br />\n$insert_matching_error" : "").
	($insert_main_error? "Failed Maintenance Calculation:<br />\n<br />\n$insert_main_error" : "").
	($update_ew_err? "\nError crediting $vars[ewallet_title]:\n\n$update_ew_err" : "").
	($insert_ewrec_err? "\nError crediting $vars[ewallet_title] transactin record:\n\n$insert_ewrec_err" : "").
	($update_sw_err? "\nError crediting $vars[swallet_title]:\n\n$update_sw_err" : "").
	($insert_swrec_err? "\nError crediting $vars[swallet_title] transactin record:\n\n$insert_swrec_err" : "");
	
	return array('status'=>$status, 'errmsg'=>$errmsg);
}
?>